﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace BibMan.util {

    public class ObservableDictionary<TKey, TValue> : Dictionary<TKey, TValue> {
        
        public delegate void ClearedHandler();
        public delegate void ElementHandler(TKey key, TValue value);
        public delegate void ElementUpdateHandler(TKey key, TValue oldValue, TValue newValue);
        public delegate void KeyChangedHandler(TKey newKey, TKey oldKey);

        public event ClearedHandler Cleared;
        protected void FireCleared() {
            if (Cleared != null) Cleared();
        }
        public event ElementHandler Added;
        protected void FireAdded(TKey key, TValue value) {
            if (Added != null) Added(key, value);
        }
        public event ElementHandler Removed;
        protected void FireRemoved(TKey key, TValue value) {
            if (Removed != null) Removed(key, value);
        }
        public event ElementUpdateHandler Updated;
        protected void FireUpdated(TKey key, TValue oldValue, TValue newValue) {
            if (Updated != null) Updated(key, oldValue, newValue);
        }
        public event KeyChangedHandler KeyChanged;
        protected void FireKeyChanged(TKey oldKey, TKey newKey) {
            if (KeyChanged != null) KeyChanged(oldKey, newKey);
        }

        public new TValue this[TKey key] {
            get {
                return base[key];
            }
            set {
                TValue old = this[key];
                base[key] = value;
                FireUpdated(key, old, value);
            }
        }

        public new void Add(TKey key, TValue value) {
            base.Add(key, value);
            FireAdded(key, value);
        }

        public new bool Remove(TKey key) {
            if (this.ContainsKey(key)) {
                TValue value = this[key];
                if (base.Remove(key)) {
                    FireRemoved(key, value);
                    return true;
                }
            }
            return false;
        }

        public new bool ChangeKey(TKey oldKey, TKey newKey) {
            if (oldKey.Equals(newKey)) return false;
            if (this.ContainsKey(newKey)) {
                throw new ArgumentException(
                    String.Format(
                    "Item has already been added. Key in dictionary: {0}  Key being added: {1}", newKey, newKey),
                    "newKey");
            }
            if (this.ContainsKey(oldKey)) {
                TValue value = this[oldKey];
                if (base.Remove(oldKey)) {
                    base.Add(newKey, value);
                    FireKeyChanged(oldKey, newKey);
                    return true;
                }
            }
            return false;
        }

        public new void Clear() {
            base.Clear();
            FireCleared();
        }
    }
}
